﻿
using ChholCmdPort;
using System;
using System.Collections.Generic;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Xsl;

namespace ChholConfig {
	public static class ChholCode {
		static public readonly string cmd_desc =
@"输入命令需要具有发送目标和分组的数据，形如
000C.112: 12 23 A1 56 /H |255
目标后的数据为发送数据，通常以16进制输入，此外：
	“|”后续的数据以十进制表示；
	“w”后续的数据以十进制表示，但是解析为2个byte；
	“q”后续的数据以十进制表示，但是解析为4个byte；
	“/”后续的数据以ASCII码显示；
	如果整个命令的开头为“$”则以UTF-8编码发送后续的全部内容；
特殊地址中：
	FFFF为广播；
	FFF0为本机回环地址；
	FFF1为单跳广播；(尚未实现)
";
		static readonly char[] split_strs = { ' ', '\t' };


		static public string codeToPkg(string chhol_code, byte from_port, out ChholCmdPort.Pkg pkg) {
			pkg = null;
			if (from_port > 100) {
				return $"源端口值({from_port})超出范围，源端口应该小于100，100为调试默认端口，101~127号端口为保留端口。";
			}
			//首先解析地址
			int destination_spec = chhol_code.IndexOf(':');
			if (destination_spec == -1) {
				return "没有找到目标地址（以“:”分割）";
			}
			string desc_str = chhol_code.Substring(0, destination_spec);
			int dot_spec = desc_str.IndexOf('.');
			if (dot_spec == -1) {
				return "在目标地址中，需要“.”分割端口和目标地址。";
			}

			//获取目标地址和端口
			ushort addr;
			if (false == UInt16.TryParse(desc_str.Substring(0, dot_spec), System.Globalization.NumberStyles.HexNumber, null, out addr)) {
				return $"目标地址解析失败。({desc_str.Substring(0, dot_spec)})";
			}
			byte to_port;
			if (false == Byte.TryParse(desc_str.Substring(dot_spec + 1), out to_port)) {
				return $"目标端口解析失败。({desc_str.Substring(dot_spec + 1)})";
			}
			if (to_port >= 128) {
				return $"目标端口值超出范围({to_port})，Chhol的端口都小于128。";
			}
			string warning;
			var send_data = strToByteArray(chhol_code.Substring(destination_spec + 1), out warning);
			if (warning != null) {
				return warning;
			}
			//构造包
			try {
				pkg = new Pkg();
				pkg.From_port = from_port;
				pkg.To_port = to_port;
				pkg.Remote_addr = addr;
				pkg.Data_len = send_data.len;
				for (int i = 0; i < send_data.len; i++) {
					pkg[i] = send_data.ba[i];
				}
			}catch(Exception e) {
				pkg = null;
				return $"构造包失败。{e.Message}";
			}
			return null;
		}
		static Encoder ec = Encoding.UTF8.GetEncoder();
		/// <summary>
		/// 按照规则将字符串转换为对应的数组
		/// </summary>
		/// <param name="str">需要转换的字符串</param>
		/// <returns>如果转换成功，则返回List byte，否则返回错误原因的字符串。</returns>
		static (byte[] ba, int len) strToByteArray(string str, out string warning) {
			warning = null;
			str = str.Trim();
			if (str == "") {
				return (new byte[0], 0);
			}else if (str.Substring(0, 1) == "$") {
				byte[] ba = new byte[Cc9d.Pkg.PKG_SIZE];
				char[] chars = str.Substring(1).ToCharArray();
				try {
					int len = ec.GetBytes(chars, 0, chars.Length, ba, 0, true);
					return (ba, len);
				} catch (ArgumentException) {
					warning = $"要发送的数据太多了，超过了{ba.Length}Byte。";
					return (null, 0);
				}
			} else {
				List<byte> b_list = new List<byte>();
				//填充数据
				string[] ss = str.Split(split_strs, StringSplitOptions.RemoveEmptyEntries);
				foreach (string s in ss) {
					//如果以“|”开头，则解析为十进制数据
					if(s.StartsWith("|")) {
						if (s.Length < 2) {
							warning = $"按照十进制数据解析失败。({s})";
							return (null, 0);
						}
						if (false == Byte.TryParse(s.Substring(1), out byte b)) {
							warning = $"按照十进制数据解析失败。({s})";
							return (null, 0);
						}
						b_list.Add(b);
					}else if(s.StartsWith("w") ){//作为十进制，解析为2个byte
						if (s.Length < 2) {
							warning = $"按照十进制数据解析为二比特失败。({s})";
							return (null, 0);
						}
						if (false == UInt16.TryParse(s.Substring(1), out ushort us)) {
							warning = $"按照十进制数据解析为二比特失败。({s})";
							return (null, 0);
						}
						b_list.Add((byte)(us & 0xFF));
						b_list.Add((byte)(us >> 8));
					}else if(s.StartsWith("q")) {//作为十进制，解析为4个byte
						if (s.Length < 2) {
							warning = $"按照十进制数据解析为四比特失败。({s})";
							return (null, 0);
						}
						if (false == UInt32.TryParse(s.Substring(1), out uint ui)) {
							warning = $"按照十进制数据解析为四比特失败。({s})";
							return (null, 0);
						}
						b_list.Add((byte)(ui & 0xFF));
						b_list.Add((byte)((ui >> 8) & 0xFF));
						b_list.Add((byte)((ui >> 16) & 0xFF));
						b_list.Add((byte)(ui >> 24));
					} else if (s.StartsWith("/")) {//作为ASCII码
						if (s.Length != 2) {
							warning = $"只能转换单个字符({s})";
							return (null, 0);
						}
						b_list.Add((byte)s.ToCharArray()[1]);
					} else {//作为十六进制
						string hex = s;
						//如果字符串长度是奇数，则在最前面补0
						if (hex.Length % 2 == 1) {
							hex = "0" + hex;
						}
						//将字符串分解为2个字符一组，转换为byte
						for (int i = 0; i < hex.Length; i += 2) {
							if (false == Byte.TryParse(hex.Substring(i, 2), System.Globalization.NumberStyles.HexNumber, null, out byte b)) {
								warning = $"按照十六进制数据解析失败。({s})";
								return (null, 0);
							}
							b_list.Add(b);
						}
					}
				}
				byte[] ba = b_list.ToArray();
				return (ba, ba.Length);
			}
		}
	}
}
